/*
 * main.cpp
 *
 *  Created on: Jan 7, 2011
 *      Author: blyth
 */

#include "InlineStream.h"
#include <time.h>
#include <cmath>
#include <iostream>
using namespace std;

const int dataDelay = 0, dataSumDelay = 1, data2SumDelay = 2, DRSTRSDelay = 3, corrDelay = 4;

const int bufferSize = 100; ////
const int numVars = 5; ////
int delays[numVars] = { 0, 3, 3, 3, 8 }; ////
long long infoBuffer[numVars][bufferSize];

int delayPos = 0;

void printRow() {
	for (int i = 0; i < numVars; i++) {
		cout << infoBuffer[i][delayPos];
		//		printf("%lld", infoBuffer[i][delayPos]);
		if (i < numVars - 1)
			cout << "\t";
		else
			cout << endl;
	}
}

void setInfo(long long val, const int index, int offset = 20) {
	int pos = delayPos + delays[index] + offset;
	if (pos >= bufferSize)
		pos = pos % bufferSize;
	infoBuffer[index][pos] = val;
}

void incr() {
	delayPos++;
	if (delayPos >= bufferSize)
		delayPos = 0;
}

int main(int argc, char** argv) {
	for (int i = 0; i < numVars; i++)
		for (int j = 0; j < bufferSize; j++)
			infoBuffer[i][j] = 0;

	unsigned int const sourceRefSize = 44;
	double* const sourceRef =
			new double[sourceRefSize] { 0.00229951, 0.0217842, 0.0613074, 0.156733, 0.305301, 0.49182, 0.68358,
					0.845512, 0.950986, 0.984521, 0.944636, 0.842791, 0.687357, 0.527077, 0.380956, 0.260087, 0.168696,
					0.105998, 0.0685462, 0.0484331, 0.0353872, 0.0332753, 0.0334183, 0.0331892, 0.0318952, 0.0299273,
					0.0283969, 0.0277491, 0.0273934, 0.0265412, 0.0250565, 0.0232322, 0.0213166, 0.0190748, 0.0159684,
					0.0131479, 0.0104398, 0.00725754, 0.00329131, 0.00210918, 0.00147583, 0.000903992, 0.000475297,
					0.000122942 };

	unsigned int const numSamples = 20000; ////
	unsigned int const numPeaks = 200; ////
	unsigned long const seed = 974488; ////
	InlineStream IS(numSamples, numPeaks, seed, sourceRef, sourceRefSize);

	////////

	char const referenceSize = 21;
	unsigned long refTimesSize[referenceSize] = { 27, 77, 196, 381, 615, 854, 1056, 1188, 1230, 1180, 1053, 859, 659,
			476, 325, 211, 132, 86, 61, 44, 42 };

	unsigned long dataSum = 0;
	unsigned long data2Sum = 0;

	for (int i = 0; i < referenceSize; i++) {
		dataSum += (IS.stream)[i];
		data2Sum += (IS.stream)[i] * (IS.stream)[i];
		if (i < referenceSize - 1) {
			for (int j = 0; j < i; j++)
				setInfo(dataSum, dataSumDelay, i);
			setInfo(data2Sum, data2SumDelay, i);
		}
	}

	unsigned long const NSMRS = numSamples - referenceSize;
	unsigned long const RSTR2SMOTT = 91394;

	for (int i = 0; i < NSMRS; i++) {
		unsigned short* const tempStream = &(IS.stream)[i];
		setInfo(tempStream[0], dataDelay, 0);
		setInfo(dataSum, dataSumDelay);
		setInfo(data2Sum, data2SumDelay);

		unsigned long DRSTRS = tempStream[0] * refTimesSize[0] + tempStream[1] * refTimesSize[1] + tempStream[2]
				* refTimesSize[2] + tempStream[3] * refTimesSize[3] + tempStream[4] * refTimesSize[4] + tempStream[5]
				* refTimesSize[5] + tempStream[6] * refTimesSize[6] + tempStream[7] * refTimesSize[7] + tempStream[8]
				* refTimesSize[8] + tempStream[9] * refTimesSize[9] + tempStream[10] * refTimesSize[10]
				+ tempStream[11] * refTimesSize[11] + tempStream[12] * refTimesSize[12] + tempStream[13]
				* refTimesSize[13] + tempStream[14] * refTimesSize[14] + tempStream[15] * refTimesSize[15]
				+ tempStream[16] * refTimesSize[16] + tempStream[17] * refTimesSize[17] + tempStream[18]
				* refTimesSize[18] + tempStream[19] * refTimesSize[19] + tempStream[20] * refTimesSize[20];

		setInfo(DRSTRS, DRSTRSDelay);

		long DRSTRSMDS = DRSTRS - (dataSum << 9);
		//		unsigned long finalLeft1 = ((DRSTRSMDS * DRSTRSMDS) >> 64) & 0x3f;
		//		cout << finalLeft1 << endl;
		unsigned long long finalLeft = DRSTRSMDS * DRSTRSMDS;
		//		unsigned long finalRight1 = ((RSTR2SMOTT * (referenceSize * data2Sum - dataSum * dataSum)) >> 64) & 0x3f;
		//		cout << finalRight1 << endl;
		unsigned long long finalRight = RSTR2SMOTT * (referenceSize * data2Sum - dataSum * dataSum);
		if (finalLeft >= finalRight && DRSTRS > (dataSum << 9))
			setInfo(1, corrDelay);
		else
			setInfo(0, corrDelay);

		printRow();
		incr();

		dataSum += tempStream[referenceSize] - tempStream[0];
		data2Sum += tempStream[referenceSize] * tempStream[referenceSize] - tempStream[0] * tempStream[0];
	}

	return 0;
}
